home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 15 / CU Amiga Magazine's Super CD-ROM 15 (1997)(EMAP Images)(GB)[!][issue 1997-10].iso / CUCD / Graphics / Ghostscript / source / gxclpath.c < prev    next >
C/C++ Source or Header  |  1997-06-12  |  35KB  |  1,160 lines

  1. /* Copyright (C) 1995, 1996, 1997 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gxclpath.c */
  20. /* Higher-level path operations for band lists */
  21. #include "math_.h"
  22. #include "memory_.h"
  23. #include "gx.h"
  24. #include "gpcheck.h"
  25. #include "gserrors.h"
  26. #include "gxdevice.h"
  27. #include "gxdevmem.h"            /* must precede gxcldev.h */
  28. #include "gxcldev.h"
  29. #include "gxclpath.h"
  30. #include "gxcolor2.h"
  31. #include "gxpaint.h"            /* for gx_fill/stroke_params */
  32. #include "gzpath.h"
  33. #include "gzcpath.h"
  34.  
  35. #define cdev cwdev
  36.  
  37. /* Statistics */
  38. #ifdef DEBUG
  39. ulong cmd_diffs[5];
  40. #endif
  41.  
  42. /* Forward declarations */
  43. private int cmd_put_path(P8(gx_device_clist_writer *cldev,
  44.   gx_clist_state *pcls, const gx_path *ppath, fixed ymin, fixed ymax, byte op,
  45.   bool implicit_close, segment_notes keep_notes));
  46. /* Driver procedures */
  47. private dev_proc_fill_path(clist_fill_path);
  48. private dev_proc_stroke_path(clist_stroke_path);
  49.  
  50. /* ------ Define the extensions to the command set ------ */
  51.  
  52. #ifdef DEBUG
  53. private const char *cmd_misc2_op_names[16] = { cmd_misc2_op_name_strings };
  54. private const char *cmd_segment_op_names[16] = { cmd_segment_op_name_strings };
  55. private const char *cmd_path_op_names[16] = { cmd_path_op_name_strings };
  56. #endif
  57.  
  58. /* Initialize the extensions to the command name table. */
  59. void
  60. gs_clpath_init(gs_memory_t *mem)
  61. {
  62. #ifdef DEBUG
  63.     cmd_op_names[cmd_op_misc2 >> 4] = "(misc2)";
  64.     cmd_sub_op_names[cmd_op_misc2 >> 4] = cmd_misc2_op_names;
  65.     cmd_op_names[cmd_op_segment >> 4] = "(segment)";
  66.     cmd_sub_op_names[cmd_op_segment >> 4] = cmd_segment_op_names;
  67.     cmd_op_names[cmd_op_path >> 4] = "(path)";
  68.     cmd_sub_op_names[cmd_op_path >> 4] = cmd_path_op_names;
  69. #endif
  70.     gs_clist_device_procs.fill_path = clist_fill_path;
  71.     gs_clist_device_procs.stroke_path = clist_stroke_path;
  72.     cmd_opvar_disable_clip = cmd_opv_disable_clip;
  73.     cmd_opvar_enable_clip = cmd_opv_enable_clip;
  74. }
  75.  
  76. /* ------ Utilities ------ */
  77.  
  78. /* Write out the color for filling, stroking, or masking. */
  79. /* We should be able to share this with clist_tile_rectangle, */
  80. /* but I don't see how to do it without adding a level of procedure. */
  81. int
  82. cmd_put_drawing_color(gx_device_clist_writer *cldev, gx_clist_state *pcls,
  83.   const gx_drawing_color *pdcolor)
  84. {    const gx_strip_bitmap *tile;
  85.     gx_color_index color0, color1;
  86.     ulong offset_temp;
  87.  
  88.     if ( gx_dc_is_pure(pdcolor) )
  89.       { gx_color_index color1 = gx_dc_pure_color(pdcolor);
  90.         if ( color1 != pcls->colors[1] )
  91.           { int code = cmd_set_color1(cldev, pcls, color1);
  92.             if ( code < 0 )
  93.           return code;
  94.           }
  95. #ifdef FUTURE
  96.         return cmd_dc_type_pure;
  97. #else
  98.         return 0;
  99. #endif
  100.       }
  101. #ifdef FUTURE
  102.     /* Any non-pure color will require the phase. */
  103.     { int px = pdcolor->phase.x, py = pdcolor->phase.y;
  104.       if ( px != pcls->tile_phase.x || py != pcls->tile_phase.y )
  105.         {    int code = cmd_set_tile_phase(cldev, pcls, px, py);
  106.         if ( code < 0 )
  107.           return code;
  108.         }
  109.     }
  110. #endif
  111.     if ( gx_dc_is_binary_halftone(pdcolor) )
  112.       { tile = gx_dc_binary_tile(pdcolor);
  113.         color0 = gx_dc_binary_color0(pdcolor);
  114.         color1 = gx_dc_binary_color1(pdcolor);
  115.         /* Set up tile and colors as for clist_tile_rectangle. */
  116.         if ( !cls_has_tile_id(cldev, pcls, tile->id, offset_temp) )
  117.           { int depth =
  118.           (color1 == gx_no_color_index &&
  119.            color0 == gx_no_color_index ?
  120.            cldev->color_info.depth : 1);
  121.         if ( tile->id == gx_no_bitmap_id ||
  122.              clist_change_tile(cldev, pcls, tile, depth) < 0
  123.            )
  124.           return_error(-1);        /* can't cache tile */
  125.           }
  126.         if ( color1 != pcls->tile_colors[1] ||
  127.          color0 != pcls->tile_colors[0]
  128.            )
  129.           { int code = cmd_set_tile_colors(cldev, pcls, color0, color1);
  130.         if ( code < 0 )
  131.           return code;
  132.           }
  133. #ifdef FUTURE
  134.         return cmd_dc_type_ht;
  135. #endif
  136.       }
  137. #ifdef FUTURE
  138.     else if ( gx_dc_is_colored_halftone(pdcolor) ) 
  139.       { const gx_device_halftone *pdht = pdcolor->colors.colored.c_ht;
  140.         int num_comp = pdht->num_comp;
  141.         byte buf[4 + 4 * cmd_max_intsize(sizeof(pdcolor->colors.colored.c_level[0]))];
  142.         byte *bp = buf;
  143.         int i;
  144.         uint short_bases = 0;
  145.         ulong bases = 0;
  146.         byte *dp;
  147.  
  148.         /****** HOW TO TELL IF COLOR IS ALREADY SET? ******/
  149.         if ( pdht->id != cldev->device_halftone_id )
  150.           { int code = cmd_put_halftone(cldev, pdht, pdht->type);
  151.             if ( code < 0 )
  152.           return code;
  153.         cldev->device_halftone_id = pdht->id;
  154.           }
  155.         for ( i = 0; i < num_comp; ++i )
  156.           { uint base = pdcolor->colors.colored.c_base[i];
  157.             if ( base > 31 )
  158.           return_error(gs_error_rangecheck);
  159.         bases |= base << ((3 - i) * 5);
  160.         short_bases |= base << (3 - i);
  161.           }
  162.         if ( bases & 0xf7bde )
  163.           { /* Some base value requires more than 1 bit. */
  164.         *bp++ = 0x10 + (byte)(bases >> 16);
  165.         *bp++ = (byte)(bases >> 8);
  166.         *bp++ = (byte)bases;
  167.           }
  168.         else
  169.           { /* The bases all fit in 1 bit each. */
  170.         *bp++ = 0x00 + (byte)short_bases;
  171.           }
  172.         for ( i = 0; i < num_comp; ++i )
  173.           bp = cmd_put_w((uint)pdcolor->colors.colored.c_level[i], bp);
  174.         /****** IGNORE alpha ******/
  175.         set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_color, bp - buf + 1);
  176.         memcpy(dp + 1, buf, bp - buf);
  177.         return cmd_dc_type_color;
  178.       }
  179. #endif
  180.     else
  181.       return_error(-1);
  182. #ifndef FUTURE
  183.     { int px = pdcolor->phase.x, py = pdcolor->phase.y;
  184.       if ( px != pcls->tile_phase.x || py != pcls->tile_phase.y )
  185.         {    int code = cmd_set_tile_phase(cldev, pcls, px, py);
  186.         if ( code < 0 )
  187.           return code;
  188.         }
  189.     }
  190. #endif
  191.     return 0;
  192. }
  193.  
  194. /* Clear (a) specific 'known' flag(s) for all bands. */
  195. /* We must do this whenever the value of a 'known' parameter changes. */
  196. void
  197. cmd_clear_known(gx_device_clist_writer *cldev, uint known)
  198. {    ushort unknown = ~known;
  199.     gx_clist_state *pcls = cldev->states;
  200.     int i;
  201.  
  202.     for ( i = cldev->nbands; --i >= 0; ++pcls )
  203.       pcls->known &= unknown;
  204. }
  205.  
  206. /* Check whether we need to change the clipping path in the device. */
  207. bool
  208. cmd_check_clip_path(gx_device_clist_writer *cldev, const gx_clip_path *pcpath)
  209. {    if ( pcpath == NULL )
  210.       return false;
  211.     /* The clip path might have moved in memory, so even if the */
  212.     /* ids match, update the pointer. */
  213.     cldev->clip_path = pcpath;
  214.     if ( pcpath->id == cldev->clip_path_id )
  215.       return false;
  216.     cldev->clip_path_id = pcpath->id;
  217.     return true;
  218. }
  219.  
  220. /* Construct the parameters for writing out a matrix. */
  221. /* We need a buffer of at least 1 + 6 * sizeof(float) bytes. */
  222. byte *
  223. cmd_for_matrix(byte *cbuf, const gs_matrix *pmat)
  224. {        byte *cp = cbuf + 1;
  225.         byte b = 0;
  226.         float coeffs[6];
  227.         int i;
  228.  
  229.         coeffs[0] = pmat->xx;
  230.         coeffs[1] = pmat->xy;
  231.         coeffs[2] = pmat->yx;
  232.         coeffs[3] = pmat->yy;
  233.         coeffs[4] = pmat->tx;
  234.         coeffs[5] = pmat->ty;
  235.         for ( i = 0; i < 4; i += 2 )
  236.           { float u = coeffs[i], v = coeffs[i^3];
  237.         b <<= 2;
  238.         if ( u != 0 || v != 0 )
  239.           { memcpy(cp, &u, sizeof(float));
  240.             cp += sizeof(float);
  241.             if ( v == u )
  242.               b += 1;
  243.             else if ( v == -u )
  244.               b += 2;
  245.             else
  246.               { b += 3;
  247.             memcpy(cp, &v, sizeof(float));
  248.             cp += sizeof(float);
  249.               }
  250.           }
  251.           }
  252.         for ( ; i < 6; ++i )
  253.           { float v = coeffs[i];
  254.         b <<= 1;
  255.         if ( v != 0 )
  256.           { ++b;
  257.             memcpy(cp, &v, sizeof(float));
  258.             cp += sizeof(float);
  259.           }
  260.           }
  261.         cbuf[0] = b << 2;
  262.         return cp;
  263. }
  264.  
  265. /* Write out values of any unknown parameters. */
  266. int
  267. cmd_write_unknown(gx_device_clist_writer *cldev, gx_clist_state *pcls,
  268.   uint must_know)
  269. {    ushort unknown = ~pcls->known & must_know;
  270.  
  271.     if ( unknown & flatness_known )
  272.       { byte *dp;
  273.         set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_flatness,
  274.                1 + sizeof(float));
  275.         memcpy(dp + 1, &cldev->imager_state.flatness, sizeof(float));
  276.         pcls->known |= flatness_known;
  277.       }
  278.     if ( unknown & fill_adjust_known )
  279.       { byte *dp;
  280.         set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_fill_adjust,
  281.                1 + sizeof(fixed) * 2);
  282.         memcpy(dp + 1, &cldev->imager_state.fill_adjust.x, sizeof(fixed));
  283.         memcpy(dp + 1 + sizeof(fixed), &cldev->imager_state.fill_adjust.y, sizeof(fixed));
  284.         pcls->known |= fill_adjust_known;
  285.       }
  286.     if ( unknown & ctm_known )
  287.       { byte cbuf[1 + 6 * sizeof(float)];
  288.         uint len =
  289.           cmd_for_matrix(cbuf,
  290.                  (const gs_matrix *)&cldev->imager_state.ctm) -
  291.                    cbuf;
  292.         byte *dp;
  293.  
  294.         set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_ctm, len + 1);
  295.         memcpy(dp + 1, cbuf, len);
  296.         pcls->known |= ctm_known;
  297.       }
  298.     if ( unknown & line_width_known )
  299.       { byte *dp;
  300.         float width =
  301.           gx_current_line_width(&cldev->imager_state.line_params);
  302.  
  303.         set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_line_width,
  304.                1 + sizeof(width));
  305.         memcpy(dp + 1, &width, sizeof(width));
  306.         pcls->known |= line_width_known;
  307.       }
  308.     if ( unknown & miter_limit_known )
  309.       { byte *dp;
  310.         set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_miter_limit,
  311.                1 + sizeof(float));
  312.         memcpy(dp + 1, &cldev->imager_state.line_params.miter_limit, sizeof(float));
  313.         pcls->known |= miter_limit_known;
  314.       }
  315.     if ( unknown & misc0_known )
  316.       { byte *dp;
  317.         set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_misc2, 2);
  318.         dp[1] = cmd_set_misc2_cap_join +
  319.           (cldev->imager_state.line_params.cap << 3) +
  320.           cldev->imager_state.line_params.join;
  321.         pcls->known |= misc0_known;
  322.       }
  323.     if ( unknown & misc1_known )
  324.       { byte *dp;
  325.         set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_misc2, 2);
  326.         dp[1] = cmd_set_misc2_ac_op_sa +
  327.           (cldev->imager_state.accurate_curves ? 4 : 0) +
  328.           (cldev->imager_state.overprint ? 2 : 0) +
  329.           (cldev->imager_state.stroke_adjust ? 1 : 0);
  330.         pcls->known |= misc1_known;
  331.       }
  332.     if ( unknown & dash_known )
  333.       { byte *dp;
  334.         int n = cldev->imager_state.line_params.dash.pattern_size;
  335.  
  336.         set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_dash,
  337.                2 + (n + 2) * sizeof(float));
  338.         dp[1] = n + (cldev->imager_state.line_params.dash.adapt ? 0x80 : 0) +
  339.           (cldev->imager_state.line_params.dot_length_absolute ? 0x40 : 0);
  340.         memcpy(dp + 2, &cldev->imager_state.line_params.dot_length,
  341.            sizeof(float));
  342.         memcpy(dp + 2 + sizeof(float),
  343.            &cldev->imager_state.line_params.dash.offset,
  344.            sizeof(float));
  345.         if ( n != 0 )
  346.           memcpy(dp + 2 + sizeof(float) * 2,
  347.              cldev->imager_state.line_params.dash.pattern,
  348.              n * sizeof(float));
  349.         pcls->known |= dash_known;
  350.       }
  351.     if ( unknown & clip_path_known )
  352.       { /* We can write out the clipping path either as rectangles */
  353.         /* or as a real (filled) path. */
  354.         const gx_clip_path *pcpath = cldev->clip_path;
  355.         int band_height = cldev->page_band_height;
  356.         int ymin = (pcls - cldev->states) * band_height;
  357.         int ymax = min(ymin + band_height, cldev->height);
  358.         gs_fixed_rect box;
  359.         byte *dp;
  360.  
  361.         set_cmd_put_op(dp, cldev, pcls, cmd_opv_begin_clip, 1);
  362.         if ( pcpath->segments_valid )
  363.           { int code;
  364.  
  365.             if ( gx_path_is_rectangle(&pcpath->path, &box) &&
  366.              fixed_is_int(box.p.x | box.p.y | box.q.x | box.q.y)
  367.            )
  368.           { /* Write the path as a rectangle. */
  369.             code = cmd_write_rect_cmd(cldev, pcls, cmd_op_fill_rect,
  370.                           fixed2int_var(box.p.x),
  371.                           fixed2int_var(box.p.y),
  372.                           fixed2int(box.q.x - box.p.x),
  373.                           fixed2int(box.q.y - box.p.y));
  374.           }
  375.             else
  376.           { /* Write the path. */
  377.             code = cmd_put_path(cldev, pcls, &pcpath->path,
  378.                     int2fixed(ymin - 1),
  379.                     int2fixed(ymax + 1),
  380.                     (pcpath->rule == gx_rule_even_odd ?
  381.                      cmd_opv_eofill : cmd_opv_fill),
  382.                     true, sn_not_first);
  383.           }
  384.         if ( code < 0 )
  385.           return code;
  386.           }
  387.         else
  388.           { /* Write out the rectangles. */
  389.         const gx_clip_rect *prect = pcpath->list.head;
  390.  
  391.         if ( prect == 0 )
  392.           prect = &pcpath->list.single;
  393.         for ( ; prect != 0; prect = prect->next )
  394.           if ( prect->xmax > prect->xmin &&
  395.                prect->ymin < ymax && prect->ymax > ymin
  396.              )
  397.             { int code =
  398.             cmd_write_rect_cmd(cldev, pcls, cmd_op_fill_rect,
  399.                        prect->xmin, prect->ymin,
  400.                        prect->xmax - prect->xmin,
  401.                        prect->ymax - prect->ymin);
  402.               if ( code < 0 )
  403.             return code;
  404.             }
  405.           }
  406.         set_cmd_put_op(dp, cldev, pcls, cmd_opv_end_clip, 2);
  407.         dp[1] = (gx_cpath_is_outside(pcpath) ? 1 : 0);
  408.         pcls->clip_enabled = 1;
  409.         pcls->known |= clip_path_known;
  410.       }
  411.     if ( unknown & color_space_known )
  412.       { byte *dp;
  413.  
  414.         if ( cldev->color_space & 8 )    /* indexed */
  415.           { uint num_values = (cldev->indexed_params.hival + 1) *
  416.           gs_color_space_num_components(
  417.             (const gs_color_space *)&cldev->indexed_params.base_space);
  418.             bool use_proc = cldev->color_space & 4;
  419.         const void *map_data;
  420.         uint map_size;
  421.  
  422.         if ( use_proc )
  423.           { map_data = cldev->indexed_params.lookup.map->values;
  424.             map_size = num_values *
  425.               sizeof(cldev->indexed_params.lookup.map->values[0]);
  426.           }
  427.         else
  428.           { map_data = cldev->indexed_params.lookup.table.data;
  429.             map_size = num_values;
  430.           }
  431.             set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_color_space,
  432.             2 + cmd_sizew(cldev->indexed_params.hival) + map_size);
  433.             memcpy(cmd_put_w(cldev->indexed_params.hival, dp + 2),
  434.                map_data, map_size);
  435.           }
  436.         else
  437.           { set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_color_space, 2);
  438.           }
  439.         dp[1] = cldev->color_space;
  440.         pcls->known |= color_space_known;
  441.       }
  442.     return 0;
  443. }    
  444.  
  445. /* ------ Driver procedures ------ */
  446.  
  447. private int
  448. clist_fill_path(gx_device *dev, const gs_imager_state *pis, gx_path *ppath,
  449.   const gx_fill_params *params, const gx_drawing_color *pdcolor,
  450.   const gx_clip_path *pcpath)
  451. {    uint unknown = 0;
  452.     int y, height, y0, y1;
  453.     gs_logical_operation_t lop = pis->log_op;
  454.     byte op = (byte)
  455.       (params->rule == gx_rule_even_odd ?
  456. #ifdef FUTURE
  457.        cmd_opv_eofill : cmd_opv_fill
  458. #else
  459.        (gx_dc_is_pure(pdcolor) ? cmd_opv_eofill : cmd_opv_hteofill) :
  460.        (gx_dc_is_pure(pdcolor) ? cmd_opv_fill : cmd_opv_htfill)
  461. #endif
  462.        );
  463.     gs_fixed_point adjust;
  464.  
  465. #ifdef DEBUG
  466.     if ( gs_debug_c(',') )        /* disable path-based banding */
  467.       return gx_default_fill_path(dev, pis, ppath, params, pdcolor,
  468.                       pcpath);
  469. #endif
  470.     adjust = params->adjust;
  471.     { gs_fixed_rect bbox;
  472.       gx_path_bbox(ppath, &bbox);
  473.       y = fixed2int(bbox.p.y) - 1;
  474.       height = fixed2int_ceiling(bbox.q.y) - y + 1;
  475.       fit_fill_yh(dev, y, height);
  476.       if ( height <= 0 )
  477.         return 0;
  478.     }
  479.     y0 = y;
  480.     y1 = y + height;
  481.     if ( cdev->imager_state.flatness != params->flatness )
  482.       { unknown |= flatness_known;
  483.         cdev->imager_state.flatness = params->flatness;
  484.       }
  485.     if ( cdev->imager_state.fill_adjust.x != adjust.x ||
  486.          cdev->imager_state.fill_adjust.y != adjust.y
  487.        )
  488.       { unknown |= fill_adjust_known;
  489.         cdev->imager_state.fill_adjust = adjust;
  490.       }
  491.     if ( cmd_check_clip_path(cdev, pcpath) )
  492.       unknown |= clip_path_known;
  493.     if ( unknown )
  494.       cmd_clear_known(cdev, unknown);
  495.     BEGIN_RECT
  496.     int code;
  497.  
  498.     cmd_do_write_unknown(cdev, pcls,
  499.                  flatness_known | fill_adjust_known |
  500.                  clip_path_known);
  501.     cmd_do_enable_clip(cdev, pcls, pcpath != NULL);
  502.     if ( lop == lop_default )
  503.       { cmd_disable_lop(cdev, pcls);
  504.       }
  505.     else
  506.       { if ( lop != pcls->lop )
  507.           { code = cmd_set_lop(cdev, pcls, lop);
  508.             if ( code < 0 )
  509.           return code;
  510.           }
  511.         cmd_enable_lop(cdev, pcls);
  512.       }
  513.     code = cmd_put_drawing_color(cdev, pcls, pdcolor);
  514.     if ( code < 0 )
  515.       { /* Something went wrong, use the default implementation. */
  516.         return gx_default_fill_path(dev, pis, ppath, params, pdcolor,
  517.                     pcpath);
  518.       }
  519.     code = cmd_put_path(cdev, pcls, ppath,
  520.                 int2fixed(max(y - 1, y0)),
  521.                 int2fixed(min(y + height + 1, y1)),
  522. #ifdef FUTURE
  523.                 op + code,    /* cmd_dc_type */
  524. #else
  525.                 op,
  526. #endif
  527.                 true, sn_none /* fill doesn't need the notes */);
  528.     if ( code < 0 )
  529.       return code;
  530.     END_RECT
  531.     return 0;
  532. }
  533.  
  534. private int
  535. clist_stroke_path(gx_device *dev, const gs_imager_state *pis, gx_path *ppath,
  536.   const gx_stroke_params *params,
  537.   const gx_drawing_color *pdcolor, const gx_clip_path *pcpath)
  538. {    int pattern_size = pis->line_params.dash.pattern_size;
  539.     uint unknown = 0;
  540.     gs_fixed_rect bbox;
  541.     gs_fixed_point expansion;
  542.     int adjust_y;
  543.     int y, height, y0, y1;
  544.     gs_logical_operation_t lop = pis->log_op;
  545. #ifndef FUTURE
  546.     byte op = (byte)
  547.       (gx_dc_is_pure(pdcolor) ? cmd_opv_stroke : cmd_opv_htstroke);
  548. #endif
  549.  
  550. #ifdef DEBUG
  551.     if ( gs_debug_c(',') )        /* disable path-based banding */
  552.       return gx_default_stroke_path(dev, pis, ppath, params, pdcolor,
  553.                     pcpath);
  554. #endif
  555.     gx_path_bbox(ppath, &bbox);
  556.     /* We must use the supplied imager state, not our saved one, */
  557.     /* for computing the stroke expansion. */
  558.     if ( gx_stroke_path_expansion(pis, ppath, &expansion) < 0 )
  559.       { /* Expansion is too large: use the entire page. */
  560.         adjust_y = 0;
  561.         y = 0;
  562.         height = dev->height;
  563.       }
  564.     else
  565.       { adjust_y = fixed2int_ceiling(expansion.y) + 1;
  566.         y = fixed2int(bbox.p.y) - adjust_y;
  567.         height = fixed2int_ceiling(bbox.q.y) - y + adjust_y;
  568.         fit_fill_yh(dev, y, height);
  569.         if ( height <= 0 )
  570.           return 0;
  571.       }
  572.     y0 = y;
  573.     y1 = y + height;
  574.     /* Check the dash pattern, since we bail out if */
  575.     /* the pattern is too large. */
  576.     cdev->imager_state.line_params.dash.pattern = cdev->dash_pattern;
  577.     if ( cdev->imager_state.line_params.dash.pattern_size != pattern_size ||
  578.          (pattern_size != 0 &&
  579.           memcmp(cdev->imager_state.line_params.dash.pattern,
  580.              pis->line_params.dash.pattern,
  581.              pattern_size * sizeof(float))) ||
  582.          cdev->imager_state.line_params.dash.offset !=
  583.            pis->line_params.dash.offset ||
  584.          cdev->imager_state.line_params.dash.adapt !=
  585.            pis->line_params.dash.adapt ||
  586.          cdev->imager_state.line_params.dot_length !=
  587.            pis->line_params.dot_length ||
  588.          cdev->imager_state.line_params.dot_length_absolute !=
  589.            pis->line_params.dot_length_absolute
  590.        )
  591.       { /* Bail out if the dash pattern is too long. */
  592.         if ( pattern_size > cmd_max_dash )
  593.           return gx_default_stroke_path(dev, pis, ppath, params,
  594.                         pdcolor, pcpath);
  595.         unknown |= dash_known;
  596.         gx_set_dash(&cdev->imager_state.line_params.dash,
  597.             pis->line_params.dash.pattern,
  598.             pis->line_params.dash.pattern_size,
  599.             pis->line_params.dash.offset, NULL);
  600.         gx_set_dash_adapt(&cdev->imager_state.line_params.dash,
  601.                   pis->line_params.dash.adapt);
  602.         gx_set_dot_length(&cdev->imager_state.line_params,
  603.                   pis->line_params.dot_length,
  604.                   pis->line_params.dot_length_absolute);
  605.       }
  606.     if ( state_neq(flatness) )
  607.       { unknown |= flatness_known;
  608.         state_update(flatness);
  609.       }
  610.     if ( state_neq(fill_adjust.x) || state_neq(fill_adjust.y) )
  611.       { unknown |= fill_adjust_known;
  612.         state_update(fill_adjust);
  613.       }
  614.     if ( state_neq(ctm.xx) || state_neq(ctm.xy) ||
  615.          state_neq(ctm.yx) || state_neq(ctm.yy) ||
  616.         /* We don't actually need tx or ty, but we don't want to bother */
  617.         /* tracking them separately from the other coefficients. */
  618.          state_neq(ctm.tx) || state_neq(ctm.ty)
  619.        )
  620.       { unknown |= ctm_known;
  621.         state_update(ctm);
  622.       }
  623.     if ( state_neq(line_params.half_width) )
  624.       { unknown |= line_width_known;
  625.         state_update(line_params.half_width);
  626.       }
  627.     if ( state_neq(line_params.miter_limit) )
  628.       { unknown |= miter_limit_known;
  629.         gx_set_miter_limit(&cdev->imager_state.line_params,
  630.                    pis->line_params.miter_limit);
  631.       }
  632.     if ( state_neq(line_params.cap) || state_neq(line_params.join) )
  633.       { unknown |= misc0_known;
  634.         state_update(line_params.cap);
  635.         state_update(line_params.join);
  636.       }
  637.     if ( state_neq(accurate_curves) || state_neq(overprint) ||
  638.          state_neq(stroke_adjust)
  639.        )
  640.       { unknown |= misc1_known;
  641.         state_update(accurate_curves);
  642.         state_update(overprint);
  643.         state_update(stroke_adjust);
  644.       }
  645.     if ( cmd_check_clip_path(cdev, pcpath) )
  646.       unknown |= clip_path_known;
  647.     if ( unknown )
  648.       cmd_clear_known(cdev, unknown);
  649.     BEGIN_RECT
  650.     int code;
  651.  
  652.     cmd_do_write_unknown(cdev, pcls, stroke_all_known);
  653.     cmd_do_enable_clip(cdev, pcls, pcpath != NULL);
  654.     if ( lop == lop_default )
  655.       { cmd_disable_lop(cdev, pcls);
  656.       }
  657.     else
  658.       { if ( lop != pcls->lop )
  659.           { code = cmd_set_lop(cdev, pcls, lop);
  660.             if ( code < 0 )
  661.           return code;
  662.           }
  663.         cmd_enable_lop(cdev, pcls);
  664.       }
  665.     code = cmd_put_drawing_color(cdev, pcls, pdcolor);
  666.     if ( code < 0 )
  667.       { /* Something went wrong, use the default implementation. */
  668.         return gx_default_stroke_path(dev, pis, ppath, params, pdcolor,
  669.                       pcpath);
  670.       }
  671.     { fixed ymin, ymax;
  672.       /* If a dash pattern is active, we can't skip segments */
  673.       /* outside the clipping region, because that would throw off */
  674.       /* the pattern. */
  675.       if ( pattern_size == 0 )
  676.         ymin = int2fixed(max(y - adjust_y, y0)),
  677.         ymax = int2fixed(min(y + height + adjust_y, y1));
  678.       else
  679.         ymin = min_fixed,
  680.         ymax = max_fixed;
  681.       code = cmd_put_path(cdev, pcls, ppath, ymin, ymax,
  682. #ifdef FUTURE
  683.                   cmd_opv_stroke + code,    /* cmd_dc_type */
  684. #else
  685.                   op,
  686. #endif
  687.                   false, (segment_notes)~0);
  688.       if ( code < 0 )
  689.         return code;
  690.     }
  691.     END_RECT
  692.     return 0;
  693. }
  694.  
  695. /* ------ Path utilities ------ */
  696.  
  697. /* Define the state bookkeeping for writing path segments. */
  698. typedef struct cmd_segment_writer_s {
  699.     /* Set at initialization */
  700.   gx_device_clist_writer *cldev;
  701.   gx_clist_state *pcls;
  702.     /* Updated dynamically */
  703.   segment_notes notes;
  704.   byte *dp;
  705.   int len;
  706.   gs_fixed_point delta_first;
  707.   byte cmd[6 * (1 + sizeof(fixed))];
  708. } cmd_segment_writer;
  709.  
  710. /* Put out a path segment command. */
  711. private int near
  712. cmd_put_segment(cmd_segment_writer _ss *psw, byte op,
  713.   const fixed _ss *operands, segment_notes notes)
  714. {    const fixed _ss *optr = operands;
  715.     /* Fetch num_operands before possible command merging. */
  716.     int i = clist_segment_op_num_operands[op & 0xf];
  717.     byte *q = psw->cmd - 1;
  718.  
  719. #ifdef DEBUG
  720.     if ( gs_debug_c('L') )
  721.       { int j;
  722.         dprintf2("[L]  %s:%d:", cmd_segment_op_names[op & 0xf],
  723.              (int)notes);
  724.         for ( j = 0; j < i; ++j )
  725.           dprintf1(" %g", fixed2float(operands[j]));
  726.         dputs("\n");
  727.       }
  728. #endif
  729.  
  730.     /* Merge or shorten commands if possible. */
  731.     if ( op == cmd_opv_rlineto )
  732.       { if ( operands[0] == 0 )
  733.           op = cmd_opv_vlineto, optr = ++operands, i = 1;
  734.         else if ( operands[1] == 0 )
  735.           op = cmd_opv_hlineto, i = 1;
  736.         else
  737.           switch ( *psw->dp )
  738.         {
  739.         case cmd_opv_rmoveto:
  740.           psw->delta_first.x = operands[0];
  741.           psw->delta_first.y = operands[1];
  742.           op = cmd_opv_rmlineto;
  743. merge:          cmd_uncount_op(*psw->dp, psw->len);
  744.           cmd_shorten_op(psw->cldev, psw->pcls, psw->len); /* delete it */
  745.           q += psw->len - 1;
  746.           break;
  747.         case cmd_opv_rmlineto:
  748.           if ( notes != psw->notes )
  749.             break;
  750.           op = cmd_opv_rm2lineto;
  751.           goto merge;
  752.         case cmd_opv_rm2lineto:
  753.           if ( notes != psw->notes )
  754.             break;
  755.           if ( operands[0] == -psw->delta_first.x &&
  756.                operands[1] == -psw->delta_first.y
  757.               )
  758.             { cmd_uncount_op(cmd_opv_rm2lineto, psw->len);
  759.               *psw->dp = cmd_count_op(cmd_opv_rm3lineto, psw->len);
  760.               return 0;
  761.             }
  762.           break;
  763.         default:
  764.           ;
  765.         }
  766.       }
  767.  
  768.     for ( ; --i >= 0; ++optr )
  769.       {    fixed d = *optr, d2;
  770.         if ( is_bits(d, _fixed_shift + 11) &&
  771.              !(d & (float2fixed(0.25) - 1))
  772.            )
  773.           { cmd_count_add1(cmd_diffs[3]);
  774.             d = ((d >> (_fixed_shift - 2)) & 0x1fff) + 0xc000;
  775.             q += 2;
  776.           }
  777.         else if ( is_bits(d, 19) && i > 0 && is_bits(d2 = optr[1], 19) )
  778.           { cmd_count_add1(cmd_diffs[0]);
  779.             q[1] = (byte)((d >> 13) & 0x3f);
  780.             q[2] = (byte)(d >> 5);
  781.             q[3] = (byte)((d << 3) + ((d2 >> 16) & 7));
  782.             q[4] = (byte)(d2 >> 8);
  783.             q[5] = (byte)d2;
  784.             q += 5;
  785.             --i, ++optr;
  786.             continue;
  787.           }
  788.         else if ( is_bits(d, 22) )
  789.           { cmd_count_add1(cmd_diffs[1]);
  790.             q[1] = (byte)(((d >> 16) & 0x3f) + 0x40);
  791.             q += 3;
  792.           }
  793.         else if ( is_bits(d, 30) )
  794.           { cmd_count_add1(cmd_diffs[2]);
  795.             q[1] = (byte)(((d >> 24) & 0x3f) + 0x80);
  796.             q[2] = (byte)(d >> 16);
  797.             q += 4;
  798.           }
  799.         else
  800.           { int b;
  801.             cmd_count_add1(cmd_diffs[4]);
  802.             *++q = 0xe0;
  803.             for ( b = sizeof(fixed) - 1; b > 1; --b )
  804.               *++q = (byte)(d >> (b * 8));
  805.             q += 2;
  806.           }
  807.         q[-1] = (byte)(d >> 8);
  808.         *q = (byte)d;
  809.           }
  810.     if ( notes != psw->notes )
  811.       { byte *dp;
  812.  
  813.         set_cmd_put_op(dp, psw->cldev, psw->pcls, cmd_opv_set_misc2, 2);
  814.         dp[1] = cmd_set_misc2_notes + notes;
  815.         psw->notes = notes;
  816.       }
  817.     { int len = q + 2 - psw->cmd;
  818.       byte *dp;
  819.  
  820.       set_cmd_put_op(dp, psw->cldev, psw->pcls, op, len);
  821.       memcpy(dp + 1, psw->cmd, len - 1);
  822.       psw->len = len;
  823.       psw->dp = dp;
  824.     }
  825.     return 0;
  826. }
  827. /* Put out a line segment command. */
  828. #define cmd_put_rmoveto(psw, operands)\
  829.   cmd_put_segment(psw, cmd_opv_rmoveto, operands, sn_none)
  830. #define cmd_put_rlineto(psw, operands, notes)\
  831.   cmd_put_segment(psw, cmd_opv_rlineto, operands, notes)
  832.  
  833. /*
  834.  * Write a path.  We go to a lot of trouble to omit segments that are
  835.  * entirely outside the band.
  836.  */
  837. private int
  838. cmd_put_path(gx_device_clist_writer *cldev, gx_clist_state *pcls,
  839.   const gx_path *ppath, fixed ymin, fixed ymax, byte path_op,
  840.   bool implicit_close, segment_notes keep_notes)
  841. {    gs_path_enum cenum;
  842.     cmd_segment_writer writer;
  843.     static byte initial_op = { cmd_opv_end_run };
  844.     /*
  845.      * We define the 'side' of a point according to its Y value as
  846.      * follows:
  847.      */
  848. #define which_side(y) ((y) < ymin ? -1 : (y) >= ymax ? 1 : 0)
  849.  
  850.     /*
  851.      * While writing a subpath, we need to keep track of any segments
  852.      * skipped at the beginning of the subpath and any segments skipped
  853.      * just before the current segment.  We do this with two sets of
  854.      * state variables, one that tracks the actual path segments and one
  855.      * that tracks the emitted segments.
  856.      *
  857.      * The following track the actual segments:
  858.      */
  859.  
  860.         /*
  861.          * The point and side of the last moveto (skipped if
  862.          * start_side != 0):
  863.          */
  864.     gs_fixed_point start;
  865.     int start_side;
  866.         /*
  867.          * Whether any lines or curves were skipped immediately
  868.          * following the moveto:
  869.          */
  870.     bool start_skip;
  871.         /* The side of the last point: */
  872.     int side;
  873.         /* The last point with side != 0: */
  874.     gs_fixed_point out;
  875.         /* If the last out-going segment was a lineto, */
  876.         /* its notes: */
  877.     segment_notes out_notes;
  878.  
  879.     /*
  880.      * The following track the emitted segments:
  881.      */
  882.  
  883.         /* The last point emitted: */
  884.     fixed px = int2fixed(pcls->rect.x);
  885.     fixed py = int2fixed(pcls->rect.y);
  886.         /* The point of the last emitted moveto: */
  887.     gs_fixed_point first;
  888.         /* Information about the last emitted operation: */
  889.     int open = 0;        /* -1 if last was moveto, 1 if line/curveto, */
  890.                 /* 0 if newpath/closepath */
  891.  
  892.  
  893.     if_debug4('p', "[p]initial (%g,%g), clip [%g..%g)\n",
  894.           fixed2float(px), fixed2float(py),
  895.           fixed2float(ymin), fixed2float(ymax));
  896.     gx_path_enum_init(&cenum, ppath);
  897.     writer.cldev = cldev;
  898.     writer.pcls = pcls;
  899.     writer.notes = sn_none;
  900. #define set_first_point() (writer.dp = &initial_op)
  901. #define first_point() (writer.dp == &initial_op)
  902.     set_first_point();
  903.     for ( ; ; )
  904.       { fixed vs[6];
  905. #define A vs[0]
  906. #define B vs[1]
  907. #define C vs[2]
  908. #define D vs[3]
  909. #define E vs[4]
  910. #define F vs[5]
  911.         int pe_op = gx_path_enum_next(&cenum, (gs_fixed_point *)vs);
  912.         byte *dp;
  913.         int code;
  914.  
  915.         switch ( pe_op )
  916.           {
  917.           case 0:
  918.         /* If the path is open and needs an implicit close, */
  919.         /* do the close and then come here again. */
  920.         if ( open > 0 && implicit_close )
  921.           goto close;
  922.         /* All done. */
  923.         pcls->rect.x = fixed2int_var(px);
  924.         pcls->rect.y = fixed2int_var(py);
  925.         if_debug2('p', "[p]final (%d,%d)\n",
  926.               pcls->rect.x, pcls->rect.y);
  927.         set_cmd_put_op(dp, cldev, pcls, path_op, 1);
  928.         return 0;
  929.           case gs_pe_moveto:
  930.         /* If the path is open and needs an implicit close, */
  931.         /* do a closepath and then redo the moveto. */
  932.         if ( open > 0 && implicit_close )
  933.           { gx_path_enum_backup(&cenum);
  934.             goto close;
  935.           }
  936.         open = -1;
  937.         start.x = A, start.y = B;
  938.         start_skip = false;
  939.         if ( (start_side = side = which_side(B)) != 0 )
  940.           {    out.x = A, out.y = B;
  941.             if_debug3('p', "[p]skip moveto (%g,%g) side %d\n",
  942.                   fixed2float(out.x), fixed2float(out.y),
  943.                   side);
  944.             continue;
  945.           }
  946.         C = A - px, D = B - py;
  947.         first.x = px = A, first.y = py = B;
  948.         code = cmd_put_rmoveto(&writer, &C);
  949.         if_debug2('p', "[p]moveto (%g,%g)\n",
  950.               fixed2float(px), fixed2float(py));
  951.         break;
  952.           case gs_pe_lineto:
  953.         { int next_side = which_side(B);
  954.           segment_notes notes =
  955.             gx_path_enum_notes(&cenum) & keep_notes;
  956.  
  957.           if ( next_side == side && side != 0 )
  958.             { /* Skip a line completely outside the clip region. */
  959.               if ( open < 0 )
  960.             start_skip = true;
  961.               out.x = A, out.y = B;
  962.               out_notes = notes;
  963.               if_debug3('p', "[p]skip lineto (%g,%g) side %d\n",
  964.                 fixed2float(out.x), fixed2float(out.y),
  965.                 side);
  966.               continue;
  967.             }
  968.           /* If we skipped any segments, put out a moveto/lineto. */
  969.           if ( side && (px != out.x || py != out.y || first_point()) )
  970.             { C = out.x - px, D = out.y - py;
  971.               if ( open < 0 )
  972.             { first = out;
  973.               code = cmd_put_rmoveto(&writer, &C);
  974.             }
  975.               else
  976.             code = cmd_put_rlineto(&writer, &C, out_notes);
  977.               if ( code < 0 )
  978.             return code;
  979.               px = out.x, py = out.y;
  980.               if_debug3('p', "[p]catchup %s (%g,%g) for line\n",
  981.                 (open < 0 ? "moveto" : "lineto"),
  982.                 fixed2float(px), fixed2float(py));
  983.             }
  984.           if ( (side = next_side) != 0 )
  985.             { /* Note a vertex going outside the clip region. */
  986.               out.x = A, out.y = B;
  987.             }
  988.           C = A - px, D = B - py;
  989.           px = A, py = B;
  990.           open = 1;
  991.           code = cmd_put_rlineto(&writer, &C, notes);
  992.         }
  993.         if_debug3('p', "[p]lineto (%g,%g) side %d\n",
  994.               fixed2float(px), fixed2float(py), side);
  995.         break;
  996.           case gs_pe_closepath:
  997. #ifdef DEBUG
  998.         { gs_path_enum cpenum;
  999.           gs_fixed_point cvs[3];
  1000.           int op;
  1001.           cpenum = cenum;
  1002.           switch ( op = gx_path_enum_next(&cpenum, cvs) )
  1003.             {
  1004.             case 0: case gs_pe_moveto:
  1005.               break;
  1006.             default:
  1007.               lprintf1("closepath followed by %d, not end/moveto!\n",
  1008.                    op);
  1009.             }
  1010.         }
  1011. #endif
  1012.         /* A closepath may require drawing an explicit line if */
  1013.         /* we skipped any segments at the beginning of the path. */
  1014. close:        if ( side != start_side )
  1015.           { /* If we skipped any segments, put out a moveto/lineto. */
  1016.             if ( side && (px != out.x || py != out.y || first_point()) )
  1017.               { C = out.x - px, D = out.y - py;
  1018.             code = cmd_put_rlineto(&writer, &C, out_notes);
  1019.             if ( code < 0 )
  1020.               return code;
  1021.             px = out.x, py = out.y;
  1022.             if_debug2('p', "[p]catchup line (%g,%g) for close\n",
  1023.                   fixed2float(px), fixed2float(py));
  1024.               }
  1025.             if ( open > 0 && start_skip )
  1026.               { /* Draw the closing line back to the start. */
  1027.             C = start.x - px, D = start.y - py;
  1028.             code = cmd_put_rlineto(&writer, &C, sn_none);
  1029.             if ( code < 0 )
  1030.               return code;
  1031.             px = start.x, py = start.y;
  1032.             if_debug2('p', "[p]draw close to (%g,%g)\n",
  1033.                   fixed2float(px), fixed2float(py));
  1034.               }
  1035.           }
  1036.         /*
  1037.          * We don't bother to update side because we know that the
  1038.          * next element after a closepath, if any, must be a moveto.
  1039.          * We must handle explicitly the possibility that the entire
  1040.          * subpath was skipped.
  1041.          */
  1042.         if ( implicit_close || open <= 0 )
  1043.           { open = 0;
  1044.             /*
  1045.              * Force writing an explicit moveto if the next subpath
  1046.              * starts with a moveto to the same point where this one
  1047.              * ends.
  1048.              */
  1049.             set_first_point();
  1050.             continue;
  1051.           }
  1052.         open = 0;
  1053.         px = first.x, py = first.y;
  1054.         code = cmd_put_segment(&writer, cmd_opv_closepath, &A, sn_none);
  1055.         if_debug0('p', "[p]close\n");
  1056.         break;
  1057.           case gs_pe_curveto:
  1058.         { segment_notes notes =
  1059.             gx_path_enum_notes(&cenum) & keep_notes;
  1060.         { fixed bpy, bqy;
  1061.           int all_side, out_side;
  1062.  
  1063.           /* Compute the Y bounds for the clipping check. */
  1064.           if ( B < D ) bpy = B, bqy = D;
  1065.           else bpy = D, bqy = B;
  1066.           if ( F < bpy ) bpy = F;
  1067.           else if ( F > bqy ) bqy = F;
  1068.           all_side = (bqy < ymin ? -1 : bpy > ymax ? 1 : 0);
  1069.           if ( all_side != 0 )
  1070.             { if ( all_side == side )
  1071.             { /* Skip a curve entirely outside the clip region. */
  1072.               if ( open < 0 )
  1073.                 start_skip = true;
  1074.               out.x = E, out.y = F;
  1075.               out_notes = notes;
  1076.               if_debug3('p', "[p]skip curveto (%g,%g) side %d\n",
  1077.                     fixed2float(out.x), fixed2float(out.y),
  1078.                     side);
  1079.               continue;
  1080.             }
  1081.               out_side = all_side;
  1082.             }
  1083.           else
  1084.             out_side = which_side(F);
  1085.           /* If we skipped any segments, put out a moveto/lineto. */
  1086.           if ( side && (px != out.x || py != out.y || first_point()) )
  1087.             { fixed diff[2];
  1088.               diff[0] = out.x - px, diff[1] = out.y - py;
  1089.               if ( open < 0 )
  1090.             { first = out;
  1091.               code = cmd_put_rmoveto(&writer, diff);
  1092.             }
  1093.               else
  1094.             code = cmd_put_rlineto(&writer, diff, out_notes);
  1095.               if ( code < 0 )
  1096.             return code;
  1097.               px = out.x, py = out.y;
  1098.               if_debug3('p', "[p]catchup %s (%g,%g) for curve\n",
  1099.                 (open < 0 ? "moveto" : "lineto"),
  1100.                 fixed2float(px), fixed2float(py));
  1101.             }
  1102.           if ( (side = out_side) != 0 )
  1103.             { /* Note a vertex going outside the clip region. */
  1104.               out.x = E, out.y = F;
  1105.             }
  1106.         }
  1107.         { fixed nx = E, ny = F;
  1108.           const fixed _ss *optr = vs;
  1109.           byte op;
  1110.  
  1111.           if_debug7('p', "[p]curveto (%g,%g; %g,%g; %g,%g) side %d\n",
  1112.                 fixed2float(A), fixed2float(B),
  1113.                 fixed2float(C), fixed2float(D),
  1114.                 fixed2float(E), fixed2float(F), side);
  1115.           E -= C, F -= D;
  1116.           C -= A, D -= B;
  1117.           A -= px, B -= py;
  1118.           if ( B == 0 && E == 0 )
  1119.             { B = A, E = F, optr++, op = cmd_opv_hvcurveto;
  1120.               if ( (B ^ D) >= 0 )
  1121.             { if ( C == D && E == B )
  1122.                 op = cmd_opv_hqcurveto;
  1123.             }
  1124.               else if ( C == -D && E == -B )
  1125.             C = D, op = cmd_opv_hqcurveto;
  1126.             }
  1127.           else if ( A == 0 && F == 0 )
  1128.             { optr++, op = cmd_opv_vhcurveto;
  1129.               if ( (B ^ C) >= 0 )
  1130.             { if ( D == C && E == B )
  1131.                 op = cmd_opv_vqcurveto;
  1132.             }
  1133.               else if ( D == -C && E == -B )
  1134.             op = cmd_opv_vqcurveto;
  1135.             }
  1136.           else if ( A == 0 && B == 0 )
  1137.             optr += 2, op = cmd_opv_nrcurveto;
  1138.           else if ( E == 0 && F == 0 )
  1139.             op = cmd_opv_rncurveto;
  1140.           else
  1141.             op = cmd_opv_rrcurveto;
  1142.           px = nx, py = ny;
  1143.           open = 1;
  1144.           code = cmd_put_segment(&writer, op, optr, notes);
  1145.         }
  1146.         } break;
  1147.           default:
  1148.         return_error(gs_error_rangecheck);
  1149.           }
  1150.         if ( code < 0 )
  1151.           return code;
  1152. #undef A
  1153. #undef B
  1154. #undef C
  1155. #undef D
  1156. #undef E
  1157. #undef F
  1158.       }
  1159. }
  1160.